﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Reflection;
using System.Text;
using BearUtil.Hidden;
using DocumentFormat.OpenXml.Wordprocessing;
using Sirenix.OdinInspector;
using UnityEngine;
using XNode;

// 熊熊组建ʕ•㉨•ʔ
namespace BearUtil
{
    /// <summary>
    /// 剧情内包含的对话
    /// </summary>
    [Serializable, CreateAssetMenu(fileName = "NewDialog", menuName = "Story&Dialog/Create Dialog"),
     RequireNode(typeof(StartNode), typeof(EndNode))]
    public class DialogGraph : XNode.NodeGraph, ICustomGraph
    {
        /// <summary>
        /// 关联 dialogNode
        /// </summary>
        [OnValueChanged("SyncBind")] public Node owner;

        // 编辑器上一次停留位置
        [HideInInspector] public Vector2 LastFocusPosition;

        public override Node AddNode(Type type)
        {
            Node node = null;
            // 设置 index
            switch (type.Name)
            {
                case "TalkNode":
                    node = base.AddNode(type);
                    TalkNode tn = (node as TalkNode);
                    if (tn == null)
                        return node;
                    var config = (owner as BearDialog).basic;
                    tn.FontSpeed = (int) config.audioData.FontSpeed;
                    tn.VoiceClip = config.audioData.SFX == null ? "" : config.audioData.SFX.name;
                    break;
                default:
                    node = base.AddNode(type);
                    break;
            }

            UpdateData();

            node.name = this.name + "_" + node.GetType().Name + "_" + node.GetHashCode();
            return node;
        }

        // 节点顺序
        private int sortCount = 1;
        private List<BearNode> _close;
        private List<BearNode> subNodes;

        public void UpdateData()
        {
            if (!checkNodes())
                return;

            var endNode = nodes.Find(n => n.GetType().Name.Equals("EndNode")) as BearNode;
            if (_close == null)
                _close = new List<BearNode>();

            if (subNodes == null)
                subNodes = new List<BearNode>();

            subNodes.Clear();
            _close.Clear();
            collectionNode(endNode);
            pickUpCollection();

            sortCount = 1;
            var count = _close.Count;
            for (int i = 0; i < count; i++)
            {
                _close[i].index = sortCount++;
            }

            for (int i = 0; i < count; i++)
            {
                var node = _close[i];
                var cn = node as ChoiceNode;
                if (cn == null)
                    assignDefaultNode(node);
                else
                    assignChoiceNode(cn);    
            }
            

            _close = _close.Concat(subNodes).ToList();
        }

        /// <summary>
        /// 通常节点只有一个 Output
        /// </summary>
        /// <param name="node"></param>
        private void assignDefaultNode(BearNode node)
        {
            assignSubNode(node.Outputs.First());
        }

        /// <summary>
        /// 安置 Choice node
        /// </summary>
        /// <param name="node"></param>
        private void assignChoiceNode(ChoiceNode node)
        {
            var ports = node.Outputs;
            foreach (var port in ports)
            {
                if (port.ConnectionCount == 0 || port.fieldName.Equals("next"))
                    continue;

                assignSubNode(port);
            }
        }

        /// <summary>
        /// 传入导出接口，收集一级子节点
        /// </summary>
        /// <param name="port">Output port</param>
        private void assignSubNode(NodePort port)
        {
            if (port == null)
                return;
            
            // 设置同级节点
            var connections = port.GetConnections();
            for (int j = 0; j < connections.Count; j++)
            {
                if (!_close.Contains(connections[j].node))
                {
                    var sub = connections[j].node as BearNode;
                    if (sub != null && !subNodes.Contains(sub))
                    {
                        subNodes.Add(sub);
                        sub.index = sortCount++;
                    }
                }
            }
        }

        /// <summary>
        /// 收集线性节点
        /// </summary>
        /// <param name="nextNode"></param>
        private void collectionNode(BearNode nextNode)
        {
            if (nextNode == null)
                return;
            if (!_close.Contains(nextNode))
                _close.Add(nextNode);

            var input = nextNode.Inputs.First();
            var lastPorst = input.GetConnections();
            for (int i = 0; i < lastPorst.Count; i++)
            {
                var port = lastPorst[i];

                var bn = port.node as BearNode;
                if (bn == null)
                {
                    var merge = port.node as MergeNode;
                    if (merge == null)
                    {
                        Debug.LogError($"无效节点: {name}");
                        return;
                    }
                    else
                    {
                        var outputs = merge.GetLasts();
                        foreach (var bearNode in outputs)
                            collectionNode(bearNode);
                    }
                }
                else
                {
                    if (!_close.Contains(bn))
                        _close.Add(bn);

                    collectionNode(bn);
                }
            }
        }

        /// <summary>
        /// 整理节点
        /// </summary>
        private void pickUpCollection()
        {
            if (_close == null || _close.Count <= 2)
                return;

            _close.Reverse();
            var index = _close.FindIndex(node => node.GetType().Name.Equals("StartNode"));
            if (index == 0)
                return;
            if (index < 0)
            {
                Debug.LogError("Node Error:" + name);
                return;
            }

            List<BearNode> tmp = new List<BearNode>();
            for (int i = 0; i < _close.Count; i++)
            {
                if ((_close.Count - i) > index)
                {
                    if (i < index)
                        tmp.Add(_close[i]);
                    _close[i] = _close[i + index];
                }
                else if ((_close.Count - i) <= index)
                {
                    _close[i] = tmp[index - (_close.Count - i)];
                }
            }
        }

        /// <summary>
        /// 限制规则，检测 node 内容
        /// </summary>
        private bool checkNodes()
        {
            if (nodes == null || nodes.Count <= 1)
                return false;

            /// 增加限制规则

            return true;
        }

        // 输出 Excel 数据
        public void OutputData(string outputPath)
        {
            BearDialog dialog = owner as BearDialog;
            List<DialogData> datas = new List<DialogData>();
            if (dialog == null)
            {
                Debug.LogError("数据错误： " + name);
                return;
            }

            UpdateData();
            // filename
            for (int i = 0; i < _close.Count(); i++)
            {
                var node = _close[i];
                if (node == null)
                {
                    Debug.LogError("Error BearNode Data: " + i + ":" + name);
                    continue;
                }

                if (!node.NoInputLink() || node.GetType().Name.Equals("StartNode"))
                {
                    DialogFormatUtil.SetData(out DialogData data, node);
                    datas.Add(data);
                }
            }

            // 输出 scriptableObject 数据
            var excelData = ExcelDataGenerator.GenerateExcelData<DialogData>(datas);
            if (excelData == null)
                return;

            excelData.sheetName = $"dialogue_{(owner.graph as StoryGraph).basic.id}_{(owner as BearDialog).basic.id}";
            var storyGraph = (owner.graph as StoryGraph);
            string fileName = $"dialogue_{storyGraph.basic.id}_{dialog.basic.id}";
            Utils.CreateScriptableObject(excelData, ExcelDataGenerator.Instance.ExcelDataPath, fileName);

            // 增加文件夹
            string filePath =  $"{outputPath}/{owner.graph.name}";
            ExcelEdit.WriteExcel(excelData, filePath);
        }

        
        /// <summary>
        /// Owner 改变时同步
        /// </summary>
        private void SyncBind(Node node)
        {
            if (node == null)
                return;
            
            var dialog = node as BearDialog;
            if (dialog == null)
                return;
            dialog.selfGraph = this;
        }
    }
}